#include <dicom/storage/encrypt.h>
#include <dicom/storage/decrypt.h>
#include <gwbase/base/util.h>
#include <gwbase/base/test_harness.h>
#include <gwbase/base/test_util.h>
#include <surbasic/surbasic.h>
#include <surbasic/Digestor.h>
#include <dicom/upload/same_hash_checker.h>

using namespace dicom;
using namespace SDBasic;
using namespace SDBasic::code;

class SameHashCheckerTest {};

/*
static bool LoadFakeHashEntry(HashCache* c, int i, HashEntry* e1) {
  std::string src_md5 = StringPrintf("src_md5_%d", i);
  std::string hexkey = StringPrintf("hexkey_%d", i);
  return c->GetHashEntry(src_md5, hexkey, e1);
}

static bool FindBestFakeHashEntry(HashCache* c, int i, HashEntry* e1) {
  std::string src_md5 = StringPrintf("src_md5_%d", i);
  return c->GetBestEntry(src_md5, e1);
}
*/

static const char* user = "surmd_test_1@163.com";
static const char* pwd = "aA111111";

uint64_t GetToken(const std::string& user, const std::string& password,
                  AccessToken* token) {
  uint64_t key =
      SDBasic::Login("https://open.surdoc.net", user, password, *token);
  EXPECT_TRUE(key > 0);
  return key;
}

static void PrintSameHashList(const ServerHashEntryList* list) {
  printf("---------------%ld Same Hash Info-----------\n", list->size());
  for (size_t i = 0; i < list->size(); ++i) {
    const ServerHashEntry& n = (*list)[i];
    printf("HEXKEY: %s; ENC_HASH: %s; SIZE: %ld; ENC_SIZE: %ld\n",
           n.hexkey.c_str(), n.enc_digest.c_str(), n.src_size, n.enc_size);
  }
}

const char* digestOfEmptyFile =
    "d41d8cd98f00b204e9800998ecf8427eda39a3ee5e6b4b0d3255bfef95601890afd807090";

const char* sha512OfEmptyFile =
    "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d"
    "85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";

TEST(SameHashCheckerTest, GetSameHashList) {
  AccessToken token;
  uint64_t surdoc_key = GetToken(user, pwd, &token);

  const char* dbpath = "_hash_cache_test.db";
  dicom::DeleteFile(dbpath);

  dicom::HashCache c;
  Status s = c.Open(dbpath);
  EXPECT_TRUE(s.ok());

  SameHashChecker u(&c);
  ServerHashEntryList list;
  s = u.GetServerHashEntryListFromServer(surdoc_key, digestOfEmptyFile,
                                         sha512OfEmptyFile, &list);
  EXPECT_TRUE(s.ok());

  PrintSameHashList(&list);

  // Now do a slow check
  const char* src_file = "src_file.dat";
  const char* src_md5 = "d41d8cd98f00b204e9800998ecf8427e";

  CreateTestFile(src_file, 0, false);
  bool rapid;

  // Now do a fast check
  HashEntry hash0;
  rapid = u.CanRapidUploadFastCheck(&list, src_md5, &hash0);
  EXPECT_TRUE(rapid == false);

  // Now a slow check
  HashEntry hash2;
  rapid = u.CanRapidUploadSlowCheck(&list, src_file, &hash2);
  EXPECT_TRUE(rapid);

  // Now another fast check
  HashEntry hash3;
  rapid = u.CanRapidUploadFastCheck(&list, src_md5, &hash3);
  EXPECT_TRUE(rapid);
}

TEST(SameHashCheckerTest, GetEmptySameHashList) {
  AccessToken token;
  uint64_t surdoc_key = GetToken(user, pwd, &token);

  const char* dbpath = "_hash_cache_test.db";
  dicom::DeleteFile(dbpath);

  dicom::HashCache c;
  Status s = c.Open(dbpath);
  EXPECT_TRUE(s.ok());

  const char* src_file = "src_file.dat";
  const char* enc_file = "enc_file.dat";
  CreateTestFile(src_file, 128, true);

  HashEntry hash;
  dicom::ZipAndEncryptFile(dicom::ByteArray::genRandom(32).toHexStr(), src_file,
                           enc_file, &hash);

  SameHashChecker u(&c);
  ServerHashEntryList list;
  s = u.GetServerHashEntryListFromServer(surdoc_key, hash.src_digest,
                                         hash.src_sha512, &list);
  EXPECT_TRUE(s.ok());
  EXPECT_TRUE(list.empty());
}

int main() {
  dicom::RunAllTests();
  return 0;
}
